package sch.frog.json;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

public class JSONBinder {
	private ObjectMapper mapper = new ObjectMapper();
	public static DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	
	private ObjectNode objectNode = null;
	private ArrayNode arrayNode = null;
	private JsonNode jsonNode;
	
	private void initMapperConfig() {
		mapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
		mapper.setDateFormat(dateFormat);
		
		// 设置输入时忽略JSON字符串中存在而Java对象实际没有的属性
		mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
		mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
		mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
		mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
		// 强制加双引号
		// mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
	}
	
	public JSONBinder() {
		initMapperConfig();
		// 设置输出包含的属性
		mapper.setSerializationInclusion(Include.ALWAYS);
		
		objectNode = mapper.createObjectNode();
		arrayNode = mapper.createArrayNode();
	}
	
	/**
	 * 	定制Json转换
	 * @param include
	 */
	public JSONBinder(Include include) {
		initMapperConfig();
		
		mapper.setSerializationInclusion(include);
	}

	/**
	 * 创建输出全部属性到Json字符串的Binder.
	 */
	public static JSONBinder buildNormalBinder() {
		return new JSONBinder(Include.ALWAYS);
	}

	/**
	 * 创建只输出非空属性到Json字符串的Binder.
	 */
	public static JSONBinder buildNonNullBinder() {
		return new JSONBinder(Include.NON_NULL);
	}

	/**
	 * 创建只输出初始值被改变的属性到Json字符串的Binder.
	 */
	public static JSONBinder buildNonDefaultBinder() {
		return new JSONBinder(Include.NON_DEFAULT);
	}

	/**
	 * 	创建只输出值不为null或者empty到json字符串的Binder
	 * @return
	 */
	public static JSONBinder buildNonEmptyBinder() {
		return new JSONBinder(Include.NON_EMPTY);
	}
	
	public ObjectNode fromObject(String jsonStr) {
		objectNode = mapper.createObjectNode();
		putAll(jsonToMap(jsonStr));
		return objectNode;
	}

	/**
	 * json转bean
	 * 如果JSON字符串为Null或"null"字符串,返回Null. 如果JSON字符串为"[]",返回空集合.
	 * 
	 * 如需读取集合如List/Map,且不是List<String>这种简单类型时使用如下语句: List<MyBean> beanList =
	 * binder.getMapper().readValue(listString, new TypeReference<List <MyBean>>()
	 * {});
	 */
	public <T> T jsonToBean(String jsonString, Class<T> clazz) {
		if (jsonString == null || "".equals(jsonString.trim())) {
			return null;
		}

		try {
			return mapper.readValue(jsonString, clazz);
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * json转Map
	 * @param jsonStr
	 * @return
	 */
	public Map<String, Object> jsonToMap(String jsonStr) {
		try {
			Map<String, Object> jsonMap = mapper.readValue(jsonStr, Map.class);
			return jsonMap;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 如果对象为Null,返回"null". 如果集合为空集合,返回"[]".
	 */
	public String beanToJson(Object object) {
		try {
			mapper.setSerializationInclusion(Include.NON_NULL);
			mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
			return mapper.writeValueAsString(object);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	public String toString() {
		return beanToJson(objectNode);
	}

	/**
	 * 取出Mapper做进一步的设置或使用其他序列化API.
	 */
	public ObjectMapper getMapper() {
		return mapper;
	}

//	@Deprecated
//	public <T> void flushDataByPage(List<T> list, long total) throws Exception {
//		mapper.createObjectNode().put("total", total).putPOJO("pageSize", list);
//		toJson(mapper);
//	}

//	public <T> T jsonToEntity(String jsonStr, @SuppressWarnings("rawtypes") Class clazz) {
//		try {
//			// add mapper dataformat by gw_x
//			mapper.setSerializationInclusion(Include.NON_NULL);
//			mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//			@SuppressWarnings("unchecked")
//			Object object = mapper.readValue(jsonStr, clazz);
//			return (T) object;
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//		return null;
//	}

	@SuppressWarnings("rawtypes")
	public List<Map<String, Object>> jsonToLinkedMapList(String jsonStr) {
		try {
			@SuppressWarnings("unchecked")
			List<Map<String, Object>> list = mapper.readValue(jsonStr, ArrayList.class);
			// List<Object> list = mapper.readValue(jsonStr, ArrayList.class);
			return list;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	// @SuppressWarnings("rawtypes")
	// public static List jsonToList(String jsonStr) {
	// try {
	// JavaType javaType = getCollectionType(ArrayList.class,
	// BaseUserInfo.class);
	// return mapper.readValue(jsonStr, javaType);
	// } catch (Exception e) {
	// e.printStackTrace();
	// }
	// return null;
	// }

	/**
	 * 获取泛型的Collection Type
	 * 
	 * @param collectionClass 泛型的Collection
	 * @param elementClasses  元素类
	 * @return JavaType Java类型
	 * @since 1.0
	 */
	private JavaType getCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
		return mapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
	}

	public void accumulate(String key, String value) {
		objectNode.put(key, value);
	}

	public void accumulate(String key, boolean value) {
		objectNode.put(key, value);
	}

	public void accumulate(String key, double value) {
		objectNode.put(key, value);
	}

	public void accumulate(String key, int value) {
		objectNode.put(key, value);
	}

	public void put(String key, Object obj) {
		Object object = objectNode.get(key);
		if (object != null) {
			objectNode.remove(key);
		}
		objectNode.putPOJO(key, obj);
	}

	public ArrayNode add(ObjectNode objectNode) {
		arrayNode.add(objectNode);
		return arrayNode;
	}

	public void putAll(Map<String, Object> objMap) {
		Set<String> keySet = objMap.keySet();
		for (String key : keySet) {
			put(key, objMap.get(key));
		}
	}

	public Object get(String key) {
		return objectNode.get(key);
	}

	public void clear() {
		objectNode.removeAll();
	}

	public Object getArrayObj() {
		return arrayNode;
	}

	// public void putAll(Object obj) {
	// JsonNode jsonNode = objectNode.arrayNode();
	// jsonNode.asText(JSONUtils.toJson(obj));
	// logger.debug(objectNode.pojoNode(obj).asText());
	// ;
	// }

//	public static void main(String[] args) {
//		JSONBinder jsonUtils = new JSONBinder();
//		JSONBinder json = new JSONBinder();
//		json.put("username", "ccsong");
//		json.put("password", "123456");
//		logger.debug(json.toString());
//		ArrayNode node = jsonUtils.add(json.getObjectNode());
//		System.out.println(node);
//	}

//	public static void main1(String[] args) throws Exception {
//		Map<String, Object> oMap = new HashMap<String, Object>();
//		oMap.put("username", "ccsong");
//		oMap.put("password", "123456");
//		String str = toJson(oMap);
//		logger.info(jsonToMap(str) + "");
//
//		JSONBinder jsonUtils = new JSONBinder();
//		jsonUtils.accumulate("username", "ccsong");
//		jsonUtils.accumulate("password", "123456");
//		String str1 = "{\"address\":\"sadasdasd\",\"token\":\"5BC8C0BDE3FDF03765FCF4FB67181E7C\",\"userId\":2}";
//		// logger.debug(((PerUser)JSONUtils.jsonToEntity(str1,
//		// PerUser.class)).getAddress());
//		logger.debug(jsonUtils.toString());
//		jsonUtils = new JSONBinder();
//		jsonUtils.accumulate("username", "zhangsan");
//		logger.debug(jsonUtils.toString());
//
//		jsonUtils = new JSONBinder();
//		jsonUtils.put("username", "lisi");
//		logger.debug(jsonUtils.toString());
//
//		jsonUtils = new JSONBinder();
//		// CompUser compUser = new CompUser();
//		// compUser.setAddress("11123123123123");
//		// compUser.setUserId(1);
//		// compUser.setUsername("dfdfsdf");
//		// jsonUtils.putAll(CommUtils.bean2Map(compUser));
//		logger.debug(jsonUtils.toString());
//	}

	/**
	 * 
	 * @param t
	 * @param map
	 * @return
	 * @throws Exception
	 */
	public static <T> T map2Bean(Class<T> clazz, Map<String, ?> map) throws Exception {
		// 实例化类
		T entity = (T) clazz.newInstance();
		Set<String> keys = map.keySet();
		// 变量map 赋值
		for (String key : keys) {
			String fieldName = key;
			// 判断是sql 还是hql返回的结果
			if (key.equals(key.toUpperCase())) {
				// 获取所有域变量
				Field[] fields = clazz.getDeclaredFields();
				for (Field field : fields) {
					if (field.getName().toUpperCase().equals(key))
						fieldName = field.getName();
					break;
				}
			}
			// 设置赋值
			try {
				// 参数的类型 clazz.getField(fieldName)
				Class<?> paramClass = clazz.getDeclaredField(fieldName).getType();
				// 拼装set方法名称
				String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
				// 根据名称获取方法
				Method method = clazz.getMethod(methodName, paramClass);
				// 调用invoke执行赋值
				String type = paramClass.getSimpleName();
				Object val = map.get(key);
				if (val != null) {
					if (type.equals("Date")) {
						Date date = dateFormat.parse(map.get(key).toString());
						method.invoke(entity, date);
					} else if (type.equals("Integer") || type.equals("int")) {
						method.invoke(entity, Integer.parseInt(val.toString()));
					} else if (type.equals("Double") || type.equals("double")) {
						method.invoke(entity, Double.parseDouble(val.toString()));
					} else if (type.equals("Byte")) {
						method.invoke(entity, Byte.parseByte(val.toString()));
					} else {
						method.invoke(entity, val.toString());
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		return entity;
	}

	public JsonNode getTreeNode(String jsonStr) {
		try {
			return mapper.readTree(jsonStr);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public ObjectNode getObjectNode() {
		return objectNode;
	}

	public void setObjectNode(ObjectNode objectNode) {
		this.objectNode = objectNode;
	}

	public ArrayNode getArrayNode() {
		return arrayNode;
	}

	public void setArrayNode(ArrayNode arrayNode) {
		this.arrayNode = arrayNode;
	}

	public JsonNode getJsonNode() {
		return jsonNode;
	}

	public void setJsonNode(JsonNode jsonNode) {
		this.jsonNode = jsonNode;
	}
}
